OPC Studio User's Guide and Reference
Push Data Consumption Model
Concepts > OPC Wizard Concepts > OPC Wizard Operation Model > Data Provision And Consumption Models > Push Data Consumption Model
In This Topic

General

In the push data consumption model, you write a method that fulfills the OPC Write requests. The OPC Wizard calls this method (pushes the data) when needed.

This is the more common data consumption model.

Your task as a developer is to provide the code for handling the Write request by either adding an event handler for the Write Event, or overriding the OnWrite Method. The code for handling the data push can be attached to each data variable separately, or you can use a common code on some higher level in the tree of the server nodes - for example, a folder can have code that handles all Writes for the data variables contained in the folder.

In order to indicate that you have handled the Write request, your code will call the HandleAndReturn Method on the event arguments object. Note that if you use the extension methods for configuration of data variables, the event handler added by the extension methods already does this for you.

Extension Methods for Configuration

The OPC Wizard provides extension methods that allow you to define data variables that use the push data consumption model easily, without having to deal with method overrides, or handle events. This is described in the Data Variable Configuration article. Typically, you will use some overload of the WriteFunction, WriteValueAction or WriteValueFunction method to configure the data variable for the push data consumption model. With these methods, you use .NET functions (Func<...,TResult> Delegate) or actions (Action Delegate) to specify the code that handles the request. The following example illustrates the use of the WriteValueAction method.

.NET

// This example shows how to use an action to define what happens when an OPC client writes to a data variable. This is an
// example of the push data consumption model.
// You can use any OPC UA client, including our Connectivity Explorer and OpcCmd utility, to connect to the server. 
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
// OPC client, server and subscriber examples in C# on GitHub: https://github.com/OPCLabs/Examples-OPCStudio-CSharp .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.

using System;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.NodeSpace;

namespace UAServerDocExamples._UADataVariable
{
    partial class WriteValueAction
    {
        public static void Main1()
        {
            // Instantiate the server object.
            // By default, the server will run on endpoint URL "opc.tcp://localhost:48040/".
            var server = new EasyUAServer();

            // Create a writable data variable and add an action that will be executed when the data variable is written to.
            server.Add(new UADataVariable("WriteToThisVariable").WriteValueAction<int>(value => 
                Console.WriteLine($"Value written: {value}")));

            // Start the server.
            Console.WriteLine("The server is starting...");
            server.Start();

            Console.WriteLine("The server is started.");
            Console.WriteLine("Any value written to the example data variable will be displayed on the console.");
            Console.WriteLine();

            // Let the user decide when to stop.
            Console.WriteLine("Press Enter to stop the server...");
            Console.ReadLine();

            // Stop the server.
            Console.WriteLine("The server is stopping...");
            server.Stop();

            Console.WriteLine("The server is stopped.");
        }
    }
}
' This example shows how to use an action to define what happens when an OPC client writes to a data variable. This is an
' example of the push data consumption model.
' You can use any OPC UA client, including our Connectivity Explorer and OpcCmd utility, to connect to the server. 
'
' Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
' OPC client and subscriber examples in VB.NET on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-VBNET .
' Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
' a commercial license in order to use Online Forums, and we reply to every post.

Imports System
Imports OpcLabs.EasyOpc.UA
Imports OpcLabs.EasyOpc.UA.NodeSpace

Namespace _UADataVariable
    Partial Friend Class WriteValueAction
        Shared Sub Main1()
            ' Instantiate the server object.
            ' By default, the server will run on endpoint URL "opc.tcp://localhost:48040/".
            Dim server = New EasyUAServer()

            ' Create a writable data variable and add an action that will be executed when the data variable is written to.
            server.Add(New UADataVariable("WriteToThisVariable").WriteValueAction(Of Integer)(
                Sub(value) Console.WriteLine($"Value written: {value}")))

            ' Start the server.
            Console.WriteLine("The server is starting...")
            server.Start()

            Console.WriteLine("The server is started.")
            Console.WriteLine("Any value written to the example data variable will be displayed on the console.")
            Console.WriteLine()

            ' Let the user decide when to stop.
            Console.WriteLine("Press Enter to stop the server...")
            Console.ReadLine()

            ' Stop the server.
            Console.WriteLine("The server is stopping...")
            server.Stop()

            Console.WriteLine("The server is stopped.")
        End Sub
    End Class
End Namespace

The data variable can also be made write-only, if that is your requirement. Example: Examples - Server OPC UA - Write-only value implemented using an action.

How do you choose between these three extension methods?

OPC Wizard also allows you to report Write outcome other than "Good" by throwing UAStatusCodeException from the action of the WriteValueAction Method. Although it might be tempting to use this approach, we recommend against it (except in specific cases), because throwing and catching exceptions is not efficient. For best performance, use the WriteValueFunction Method instead.

The following example illustrates the use of the WriteValueFunction method for a data variable that forces its value to be within certain range.

.NET

// This example shows how to use a function to define what happens with the value when an OPC client writes to a data
// variable. This is an example of the push data consumption model.
// You can use any OPC UA client, including our Connectivity Explorer and OpcCmd utility, to connect to the server. 
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
// OPC client, server and subscriber examples in C# on GitHub: https://github.com/OPCLabs/Examples-OPCStudio-CSharp .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.

using System;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.NodeSpace;

namespace UAServerDocExamples._UADataVariable
{
    class WriteValueFunction
    {
        public static void Main1()
        {
            // Instantiate the server object.
            // By default, the server will run on endpoint URL "opc.tcp://localhost:48040/".
            var server = new EasyUAServer();

            // Create a writable data variable and add a function that will be called when the data variable is written to.
            // The function returns a status code that indicates the outcome of the Write operation. We have chosen to only
            // allow non-negative values to be written to the variable.
            server.Add(new UADataVariable("WriteToThisVariable").WriteValueFunction<int>(
                value =>
                {
                    if (value < 0)
                    {
                        Console.WriteLine($"Value rejected: {value}");
                        return UACodeBits.BadOutOfRange;
                    }
                    Console.WriteLine($"Value written: {value}");
                    return null;    // "Good"
                }));

            // Start the server.
            Console.WriteLine("The server is starting...");
            server.Start();

            Console.WriteLine("The server is started.");
            Console.WriteLine("Any value written to the example data variable will be displayed on the console.");
            Console.WriteLine();

            // Let the user decide when to stop.
            Console.WriteLine("Press Enter to stop the server...");
            Console.ReadLine();

            // Stop the server.
            Console.WriteLine("The server is stopping...");
            server.Stop();

            Console.WriteLine("The server is stopped.");
        }
    }
}
' This example shows how to use a function to define what happens with the value when an OPC client writes to a data
' variable. This is an example of the push data consumption model.
' You can use any OPC UA client, including our Connectivity Explorer and OpcCmd utility, to connect to the server. 
'
' Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
' OPC client and subscriber examples in VB.NET on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-VBNET .
' Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
' a commercial license in order to use Online Forums, and we reply to every post.

Imports System
Imports OpcLabs.EasyOpc.UA
Imports OpcLabs.EasyOpc.UA.NodeSpace

Namespace _UADataVariable
    Partial Friend Class WriteValueFunction
        Shared Sub Main1()
            ' Instantiate the server object.
            ' By default, the server will run on endpoint URL "opc.tcp://localhost:48040/".
            Dim server = New EasyUAServer()

            ' Create a writable data variable and add a function that will be called when the data variable is written to.
            ' The function returns a status code that indicates the outcome of the Write operation. We have chosen to only
            ' allow non-negative values to be written to the variable.
            server.Add(New UADataVariable("WriteToThisVariable").WriteValueFunction(Of Integer)(
                Function(value)
                    If (value < 0) Then
                        Console.WriteLine($"Value rejected: {value}")
                        Return UACodeBits.BadOutOfRange
                    End If
                    Console.WriteLine($"Value written: {value}")
                    Return Nothing ' "Good"
                End Function
                ))


            ' Start the server.
            Console.WriteLine("The server is starting...")
            server.Start()

            Console.WriteLine("The server is started.")
            Console.WriteLine("Any value written to the example data variable will be displayed on the console.")
            Console.WriteLine()

            ' Let the user decide when to stop.
            Console.WriteLine("Press Enter to stop the server...")
            Console.ReadLine()

            ' Stop the server.
            Console.WriteLine("The server is stopping...")
            server.Stop()

            Console.WriteLine("The server is stopped.")
        End Sub
    End Class
End Namespace

If the data variable should also support writing of the status code or timestamp (or both), you will use the WriteFunction method, as illustrated in the following example.

.NET

// This example shows how to use a function to define what happens with the attribute data when an OPC client writes to a
// data variable. This is an example of the push data consumption model.
// You can use any OPC UA client, including our Connectivity Explorer and OpcCmd utility, to connect to the server. 
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
// OPC client, server and subscriber examples in C# on GitHub: https://github.com/OPCLabs/Examples-OPCStudio-CSharp .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.

using System;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.NodeSpace;

namespace UAServerDocExamples._UADataVariable
{
    partial class WriteFunction
    {
        public static void Main1()
        {
            // Instantiate the server object.
            // By default, the server will run on endpoint URL "opc.tcp://localhost:48040/".
            var server = new EasyUAServer();

            // Create a writable data variable and add a function that will be called when the data variable is written to.
            // The function returns a status code that indicates the outcome of the Write operation. We have chosen to only
            // allow "Good" and "Uncertain", non-negative values to be written to the variable.
            server.Add(new UADataVariable("WriteToThisVariable").WriteFunction<int>(
                data =>
                {
                    if (data.StatusCode.IsBad || (data.TypedValue < 0))
                    {
                        Console.WriteLine($"Attribute data rejected: {data}");
                        return UACodeBits.BadOutOfRange;
                    }
                    Console.WriteLine($"Attribute data written: {data}");
                    return null;    // "Good"
                }));

            // Start the server.
            Console.WriteLine("The server is starting...");
            server.Start();

            Console.WriteLine("The server is started.");
            Console.WriteLine("Any value written to the example data variable will be displayed on the console.");
            Console.WriteLine();

            // Let the user decide when to stop.
            Console.WriteLine("Press Enter to stop the server...");
            Console.ReadLine();

            // Stop the server.
            Console.WriteLine("The server is stopping...");
            server.Stop();

            Console.WriteLine("The server is stopped.");
        }
    }
}
' This example shows how to use a function to define what happens with the attribute data when an OPC client writes to a
' data variable. This is an example of the push data consumption model.
' You can use any OPC UA client, including our Connectivity Explorer and OpcCmd utility, to connect to the server. 
'
' Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
' OPC client and subscriber examples in VB.NET on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-VBNET .
' Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
' a commercial license in order to use Online Forums, and we reply to every post.

Imports System
Imports OpcLabs.EasyOpc.UA
Imports OpcLabs.EasyOpc.UA.NodeSpace

Namespace _UADataVariable
    Partial Friend Class WriteFunction
        Shared Sub Main1()
            ' Instantiate the server object.
            ' By default, the server will run on endpoint URL "opc.tcp://localhost:48040/".
            Dim server = New EasyUAServer()

            ' Create a writable data variable and add a function that will be called when the data variable is written to.
            ' The function returns a status code that indicates the outcome of the Write operation. We have chosen to only
            ' allow "Good" and "Uncertain", non-negative values to be written to the variable.
            server.Add(New UADataVariable("WriteToThisVariable").WriteFunction(Of Integer)(
                Function(data)
                    If data.StatusCode.IsBad OrElse (data.TypedValue < 0) Then
                        Console.WriteLine($"Attribute data rejected: {data}")
                        Return UACodeBits.BadOutOfRange
                    End If
                    Console.WriteLine($"Attribute data written: {data}")
                    Return Nothing ' "Good"
                End Function
                ))


            ' Start the server.
            Console.WriteLine("The server is starting...")
            server.Start()

            Console.WriteLine("The server is started.")
            Console.WriteLine("Any value written to the example data variable will be displayed on the console.")
            Console.WriteLine()

            ' Let the user decide when to stop.
            Console.WriteLine("Press Enter to stop the server...")
            Console.ReadLine()

            ' Stop the server.
            Console.WriteLine("The server is stopping...")
            server.Stop()

            Console.WriteLine("The server is stopped.")
        End Sub
    End Class
End Namespace

Handling Requests on Higher Levels

If your OPC server has groups of data variables with basically the same behavior, and organized in such a way that it corresponds to the node space hierarchy, you would probably want to specify the behavior just once, e.g. on the level of the folder that holds all data variables of the same kind. In such case, you cannot use the extension methods for data variable configuration (described above), and need to define the behavior by handling the Write Event, or overriding the OnWrite Method, on the higher level - in our example, the level of the folder. The following examples illustrate these approaches.

Example: Examples - Server OPC UA - Implement variable writing on folder level, with an event

Example: Examples - Server OPC UA - Implement variable writing on folder level, with inheritance

Asynchronous Completion

If the actual Write operation (to your underlying system or connected system) is performed at some later time and not inside the handler for the Write request, you must indicate this to the OPC UA client using a dedicated status code, with code bits GoodCompletesAsynchronously. The following example illustrates how it is done.

.NET

// This example shows how to indicate that the write operation completes asynchronously. This is an example of the push
// data consumption model.
// You can use any OPC UA client, including our Connectivity Explorer and OpcCmd utility, to connect to the server. 
//
// Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
// OPC client, server and subscriber examples in C# on GitHub: https://github.com/OPCLabs/Examples-OPCStudio-CSharp .
// Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
// a commercial license in order to use Online Forums, and we reply to every post.

using System;
using System.Threading;
using OpcLabs.EasyOpc.UA;
using OpcLabs.EasyOpc.UA.NodeSpace;

namespace UAServerDocExamples._UADataVariable
{
    partial class WriteFunction
    {
        public static void GoodCompletesAsynchronously()
        {
            // Instantiate the server object.
            // By default, the server will run on endpoint URL "opc.tcp://localhost:48040/".
            var server = new EasyUAServer();

            // Create a writable data variable and add a function that will be called when the data variable is written to.
            // The function returns a status code that indicates the outcome of the Write operation. Since we do not know the
            // true outcome of the write operation at the time of the function call, we return status code
            // "GoodCompletesAsynchronously".
            server.Add(new UADataVariable("WriteToThisVariable").WriteFunction<int>(
                data =>
                {
                    // The actual write operation is performed asynchronously, on a separate thread.
                    var thread = new Thread(() => Console.WriteLine($"Attribute data written: {data}"));
                    thread.Start();

                    return UACodeBits.GoodCompletesAsynchronously;
                }));

            // Start the server.
            Console.WriteLine("The server is starting...");
            server.Start();

            Console.WriteLine("The server is started.");
            Console.WriteLine("Any value written to the example data variable will be displayed on the console.");
            Console.WriteLine();

            // Let the user decide when to stop.
            Console.WriteLine("Press Enter to stop the server...");
            Console.ReadLine();

            // Stop the server.
            Console.WriteLine("The server is stopping...");
            server.Stop();

            Console.WriteLine("The server is stopped.");
        }
    }
}
' This example shows how to indicate that the write operation completes asynchronously. This is an example of the push
' data consumption model.
' You can use any OPC UA client, including our Connectivity Explorer and OpcCmd utility, to connect to the server. 
'
' Find all latest examples here: https://opclabs.doc-that.com/files/onlinedocs/OPCLabs-OpcStudio/Latest/examples.html .
' OPC client and subscriber examples in VB.NET on GitHub: https://github.com/OPCLabs/Examples-QuickOPC-VBNET .
' Missing some example? Ask us for it on our Online Forums, https://www.opclabs.com/forum/index ! You do not have to own
' a commercial license in order to use Online Forums, and we reply to every post.

Imports System
Imports System.Threading
Imports OpcLabs.EasyOpc.UA
Imports OpcLabs.EasyOpc.UA.NodeSpace

Namespace _UADataVariable
    Partial Friend Class WriteFunction
        Shared Sub GoodCompletesAsynchronously()
            ' Instantiate the server object.
            ' By default, the server will run on endpoint URL "opc.tcp://localhost:48040/".
            Dim server = New EasyUAServer()

            ' Create a writable data variable and add a function that will be called when the data variable is written to.
            ' The function returns a status code that indicates the outcome of the Write operation. Since we do not know the
            ' true outcome of the write operation at the time of the function call, we return status code
            ' "GoodCompletesAsynchronously".
            server.Add(New UADataVariable("WriteToThisVariable").WriteFunction(Of Integer)(
                Function(data)
                    ' The actual write operation Is performed asynchronously, on a separate thread.
                    Dim thread = New Thread(Sub() Console.WriteLine($"Attribute data written: {data}"))
                    thread.Start()

                    Return UACodeBits.GoodCompletesAsynchronously
                End Function
                ))


            ' Start the server.
            Console.WriteLine("The server is starting...")
            server.Start()

            Console.WriteLine("The server is started.")
            Console.WriteLine("Any value written to the example data variable will be displayed on the console.")
            Console.WriteLine()

            ' Let the user decide when to stop.
            Console.WriteLine("Press Enter to stop the server...")
            Console.ReadLine()

            ' Stop the server.
            Console.WriteLine("The server is stopping...")
            server.Stop()

            Console.WriteLine("The server is stopped.")
        End Sub
    End Class
End Namespace

Data Type Considerations 

See Variable Data Type Considerations.

See Also

Examples - Server OPC Unified Architecture

Reference

Installed Examples - Server Library